#pragma  once
#include "InetAddr.hpp"
#include "Log.hpp"
#include"Socket.hpp"
#include<functional>
#include<jsoncpp/json/json.h>
#include <jsoncpp/json/reader.h>
#include <jsoncpp/json/value.h>
#include <jsoncpp/json/writer.h>
#include <memory>
#include <sys/types.h>


using namespace SocketModule;

class Request
{
public:
    Request(){}
    Request(int x, int y, char oper)
    :   _x(x),
        _y(y),
        _oper(oper)
    {}
    
    std::string Serialize()//序列化
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter write;
        std::string s = write.write(root);
        return s;
    }

    bool Deserialize(std::string &in)// 反序列化
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if(ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }
    ~Request(){}

    int X(){return _x;}
    int Y(){return _y;}
    char Oper(){return _oper;}
private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response(){}
    Response(int result, int code)
    :   _result(result),
        _code(code)
    {}

    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::FastWriter write;
        return write.write(root);
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if(ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }
    ~Response(){}

    void SetResult(int res)
    {
        _result = res;
    }

    void SetCode(int code)
    {
        _code = code;
    }

    void ShowResult()
    {
        std::cout << "计算结果是： " << _result <<"[" << _code << "]" << std::endl;
    }

private:
    int _result;//运算结果
    int _code;//运算标识符
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request& req)>;
class ProtoCal
{
public:
    ProtoCal(){}
    ProtoCal(func_t func)
    :   _func(func)
    {}

    std::string Encode(const std::string &jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;// 应用层封装报头
    }

    bool Decode(std::string& buffer, std::string *package)  //解析报头 读取文本内容
    {
        ssize_t pos = buffer.find(sep);
        if(pos == std::string::npos)
        return false;
        std::string package_len_str = buffer.substr(0, pos);
        int package_len_int = std::stoi(package_len_str);
        int target_len = package_len_str.size() + package_len_int + 2*sep.size();
        if(buffer.size() < target_len)
        return false;

        *package = buffer.substr(pos + sep.size(), package_len_int);
        buffer.erase(0,target_len);
        return true;
    }

    void GetRequest(std::shared_ptr<Socket>& sock, InetAddr& client)
    {
        std::string buffer_queue;
        while(true)
        {
            int n = sock->Recv(&buffer_queue);
            if(n > 0)
            {
                std::string json_package;

                while(Decode(buffer_queue, &json_package))
                {
                    LOG(LogLevel::DEBUG) << client.StringAddr() << "请求" << json_package;
                    Request req;
                    bool ok = req.Deserialize(json_package);
                    if(!ok)
                    continue;

                    Response resp = _func(req);

                    std::string json_ptr = resp.Serialize();

                    std::string send_str = Encode(json_ptr);

                    sock->Send(send_str);
                }
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "client" << client.StringAddr() << "Quit";
                break;
            }
            else 
            {
                LOG(LogLevel::WARNING) << "client" << client.StringAddr() << " recv error";
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket>& client, std::string& resp_buff, Response* resp)
    {
        while(true)
        {
            int n = client->Recv(&resp_buff);
            if(n > 0)
            {
                std::string json_package;

                while(Decode(resp_buff, & json_package))
                {
                    resp->Deserialize(json_package);
                }
                return true;
            }
            else if(n == 0)
            {
                std::cout << " server quit " << std::endl;
                return false;
            }
            else 
            {
                std::cout << " recv error " << std::endl;
                return false;
            }
        }
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);

        std::string json_req = req.Serialize();

        return Encode(json_req);
    }

    ~ProtoCal(){}

private:
    func_t _func;
};